package com.example.auth.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.auth.dto.UserLoginDto;
import com.example.auth.dto.UserRegisterDto;
import com.example.auth.entity.SysRole;
import com.example.auth.entity.SysUser;
import com.example.auth.entity.SysUserRole;
import com.example.auth.mapper.SysRoleMapper;
import com.example.auth.mapper.SysUserMapper;
import com.example.auth.mapper.SysUserRoleMapper;
import com.example.auth.service.AuthService;
import com.example.auth.vo.UserInfoVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 认证服务实现类
 * 
 * @author Qoder
 * @since 2025-09-06
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {

    private final SysUserMapper sysUserMapper;
    private final SysRoleMapper sysRoleMapper;
    private final SysUserRoleMapper sysUserRoleMapper;
    private final BCryptPasswordEncoder passwordEncoder;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String register(UserRegisterDto registerDto) {
        // 1. 参数校验
        if (!registerDto.getPassword().equals(registerDto.getConfirmPassword())) {
            throw new RuntimeException("两次密码输入不一致");
        }

        // 2. 检查用户名是否已存在
        SysUser existUser = sysUserMapper.selectByUsername(registerDto.getUsername());
        if (existUser != null) {
            throw new RuntimeException("用户名已存在");
        }

        // 3. 检查邮箱是否已存在
        if (StringUtils.hasText(registerDto.getEmail())) {
            SysUser existEmail = sysUserMapper.selectByEmail(registerDto.getEmail());
            if (existEmail != null) {
                throw new RuntimeException("邮箱已被注册");
            }
        }

        // 4. 创建用户
        SysUser user = new SysUser();
        BeanUtils.copyProperties(registerDto, user);
        user.setPassword(passwordEncoder.encode(registerDto.getPassword()));
        user.setStatus(1); // 启用状态
        user.setAvatar("/default-avatar.png");
        
        if (!StringUtils.hasText(user.getNickname())) {
            user.setNickname(user.getUsername());
        }

        int result = sysUserMapper.insert(user);
        if (result <= 0) {
            throw new RuntimeException("注册失败");
        }

        // 5. 分配默认角色（普通用户）
        SysRole userRole = sysRoleMapper.selectOne(
                new LambdaQueryWrapper<SysRole>()
                        .eq(SysRole::getRoleCode, "USER")
                        .eq(SysRole::getStatus, 1)
        );
        
        if (userRole != null) {
            SysUserRole userRoleRelation = new SysUserRole();
            userRoleRelation.setUserId(user.getId());
            userRoleRelation.setRoleId(userRole.getId());
            sysUserRoleMapper.insert(userRoleRelation);
        }

        log.info("用户注册成功：{}", user.getUsername());
        return "注册成功";
    }

    @Override
    public UserInfoVo login(UserLoginDto loginDto) {
        // 1. 查询用户
        SysUser user = sysUserMapper.selectByUsername(loginDto.getUsername());
        if (user == null) {
            throw new RuntimeException("用户名或密码错误");
        }

        // 2. 检查用户状态
        if (user.getStatus() == 0) {
            throw new RuntimeException("账号已被禁用");
        }

        // 3. 验证密码
        log.debug("输入密码: {}", loginDto.getPassword());
        log.debug("数据库密码: {}", user.getPassword());
        
        if (!passwordEncoder.matches(loginDto.getPassword(), user.getPassword())) {
            log.error("密码验证失败: 输入={}, 数据库={}", loginDto.getPassword(), user.getPassword());
            throw new RuntimeException("用户名或密码错误");
        }

        // 4. 执行登录
        StpUtil.login(user.getId());

        // 5. 获取Token
        String token = StpUtil.getTokenValue();

        // 6. 更新最后登录信息
        user.setLastLoginTime(LocalDateTime.now());
        user.setLastLoginIp(getClientIp()); // 简化处理，实际项目中需要从请求中获取
        sysUserMapper.updateById(user);

        // 7. 构建返回信息
        UserInfoVo userInfo = new UserInfoVo();
        BeanUtils.copyProperties(user, userInfo);
        userInfo.setToken(token);
        userInfo.setRoles(sysUserMapper.selectRoleCodesByUserId(user.getId()));

        log.info("用户登录成功：{}", user.getUsername());
        return userInfo;
    }

    @Override
    public void logout() {
        StpUtil.logout();
        log.info("用户登出成功：{}", StpUtil.getLoginIdDefaultNull());
    }

    @Override
    public UserInfoVo getCurrentUser() {
        // 1. 获取当前登录用户ID
        Object loginId = StpUtil.getLoginIdDefaultNull();
        if (loginId == null) {
            throw new RuntimeException("用户未登录");
        }

        // 2. 查询用户信息
        Long userId = Long.valueOf(loginId.toString());
        SysUser user = sysUserMapper.selectById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        // 3. 构建返回信息
        UserInfoVo userInfo = new UserInfoVo();
        BeanUtils.copyProperties(user, userInfo);
        userInfo.setToken(StpUtil.getTokenValue());
        userInfo.setRoles(sysUserMapper.selectRoleCodesByUserId(userId));

        return userInfo;
    }

    @Override
    public String refreshToken() {
        // Sa-Token会自动刷新token，这里直接返回当前token
        return StpUtil.getTokenValue();
    }

    /**
     * 获取客户端IP（简化实现）
     */
    private String getClientIp() {
        // 在实际项目中，应该从HttpServletRequest中获取真实IP
        return "127.0.0.1";
    }
}